package com.mystudy.atomic.unsafe;

import org.junit.Test;
import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * todo: {@link Unsafe}类测试
 *
 * @Author acy
 * @Date 2019/06/07
 */
public class UnsafeTest {
	/**
	 * 无法直接拿到Unsafe对象，可以利用反射的方式
	 *
	 * @throws Exception
	 */
	@Test
	public void test() throws Exception {
		Unsafe unsafe = Unsafe.getUnsafe();
		System.out.println(unsafe);
	}

	@Test
	public void test1() throws Exception {
		Unsafe unsafe = getUnsafe();
		System.out.println(unsafe);
	}

	public static Unsafe getUnsafe() throws NoSuchFieldException, IllegalAccessException {
		Field unsafe = null;
		unsafe = Unsafe.class.getDeclaredField("theUnsafe");
		unsafe.setAccessible(true);
		return (Unsafe) unsafe.get(null);
	}

	@Test
	public void test2() throws Exception {
		ExecutorService service = Executors.newFixedThreadPool(1000);
		//无锁的实现 Counter result :8377954  Time passed in ms :169
		//Counter counter = new StupidCounter();
		//synchronized的实现 Counter result :10000000  Time passed in ms :644
		//Counter counter = new SynCounter();
		//Lock的实现  Counter result :10000000  Time passed in ms :339
		//Counter counter = new LockCounter();
		//原子的实现 Counter result :10000000 Time passed in ms :375
		//Counter counter = new AtomicCounter();
		//自定义cas实现 Counter result :10000000  Time passed in ms :1208
		Counter counter = new CasCounter();
		long start = System.currentTimeMillis();
		for (int i = 0; i < 1000; i++) {
			service.submit(new CounterRunnable(counter, 10000));
		}
		service.shutdown();
		service.awaitTermination(1, TimeUnit.HOURS);
		long end = System.currentTimeMillis();
		System.out.println("Counter result :" + counter.getCounter());
		System.out.println("Time passed in ms :" + (end - start));
	}

	interface Counter {
		void increment();

		long getCounter();
	}


	static class SynCounter implements Counter {
		private long counter = 0;

		@Override
		public synchronized void increment() {
			counter++;
		}

		@Override
		public long getCounter() {
			return this.counter;
		}
	}

	static class StupidCounter implements Counter {
		private long counter = 0;

		@Override
		public void increment() {
			counter++;
		}

		@Override
		public long getCounter() {
			return this.counter;
		}
	}

	static class LockCounter implements Counter {
		private long counter = 0;

		private final Lock lock = new ReentrantLock();

		@Override
		public void increment() {
			try {
				lock.lock();
				counter++;
			} finally {
				lock.unlock();
			}
		}

		@Override
		public long getCounter() {
			return this.counter;
		}
	}

	static class AtomicCounter implements Counter {
		private AtomicLong counter = new AtomicLong(0);

		private final Lock lock = new ReentrantLock();

		@Override
		public void increment() {
			try {
				lock.lock();
				counter.incrementAndGet();
			} finally {
				lock.unlock();
			}
		}

		@Override
		public long getCounter() {
			return counter.get();
		}
	}

	static class CasCounter implements Counter {
		private volatile long counter = 0;
		private Unsafe unsafe;
		private long offset;

		CasCounter() throws Exception {
			unsafe = getUnsafe();
			offset = unsafe.objectFieldOffset(CasCounter.class.getDeclaredField("counter"));
		}

		@Override
		public void increment() {
			long current = counter;
			while (!unsafe.compareAndSwapLong(this, offset, current, current + 1)) {
				current = counter;
			}
		}

		@Override
		public long getCounter() {
			return counter;
		}
	}

	static class CounterRunnable implements Runnable {
		private final Counter counter;
		private final int num;

		public CounterRunnable(Counter counter, int num) {
			this.counter = counter;
			this.num = num;
		}

		@Override
		public void run() {
			for (int i = 0; i < num; i++) {
				counter.increment();
			}
		}
	}
}
